<?php
/**
*   Just do a "new GuiInspector($parent_widget)"
*   and let it do it's work.
*
*   It shows you a tree of widgets, their subwidgets
*   and so. When you select a row in the widget tree,
*   the widget will be highlighted (by a black frame or
*   by changing it's background color). When you activate
*   (focus) a widget, the tree will jump to that row.
*
*   @author Christian Weiske <cweiske@cweiske.de>
*/
class Dev_GuiInspector extends GtkWindow
{
    protected $widget       = null;
    protected $modWidgets   = null;
    protected $trWidgets    = null;
    protected $lblStatus    = null;
    protected $arStyles     = null;
    protected $sigSelection = null;
    protected static $strNotRealized = '%s is not visible (not realized)';
    protected static $arSpecialWidgets = array(
        'GtkEntry', 'GtkTextView', 'GtkTreeView'
    );


    function __construct($widget = null)
    {
        parent::__construct();
        $this->buildLayout();
        $this->setWidget($widget);
        $this->show_all();
    }//function __construct($widget = null)



    function buildLayout()
    {
        $this->set_title('GUI Inspector');
//        $this->connect_simple('destroy', array('gtk', 'main_quit'));
        $this->set_size_request(500, 300);
        $this->set_name('GuiInspector');

        $this->colHighlight = new GdkColor(255, 0, 0);

        $this->trWidgets = new GtkTreeView();
        $this->trWidgets->set_name('widget tree');
        $this->modWidgets = new GtkTreeStore(Gtk::TYPE_OBJECT, Gtk::TYPE_STRING, Gtk::TYPE_STRING, Gtk::TYPE_STRING, GTK::TYPE_LONG);
        $this->trWidgets->set_model($this->modWidgets);

        $column = new GtkTreeViewColumn();
        $column->set_title('Name');
        $cell_renderer = new GtkCellRendererText();
        $column->pack_start($cell_renderer, true);
        $column->set_attributes($cell_renderer, 'text', 1);
        $column->set_resizable(true);
        $this->trWidgets->insert_column($column, 0);

        $column = new GtkTreeViewColumn();
        $column->set_title('Class');
        $cell_renderer = new GtkCellRendererText();
        $column->pack_start($cell_renderer, true);
        $column->set_attributes($cell_renderer, 'text', 2);
        $column->set_resizable(true);
        $this->trWidgets->insert_column($column, 1);

        $column = new GtkTreeViewColumn();
        $column->set_title('Parent class');
        $cell_renderer = new GtkCellRendererText();
        $column->pack_start($cell_renderer, true);
        $column->set_attributes($cell_renderer, 'text', 3);
        $column->set_resizable(true);
        $this->trWidgets->insert_column($column, 2);

        $column = new GtkTreeViewColumn();
        $column->set_title('Children');
        $cell_renderer = new GtkCellRendererText();
        $column->pack_start($cell_renderer, true);
        $column->set_attributes($cell_renderer, 'text', 4);
        $column->set_resizable(true);
        $this->trWidgets->insert_column($column, 3);

        $scrwnd = new GtkScrolledWindow();
        $scrwnd->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
        $scrwnd->add($this->trWidgets);

        $hbox = new GtkHBox();
        $btnReload = new GtkButton();
        $btnReload->add(GtkImage::new_from_stock(Gtk::STOCK_REFRESH, Gtk::ICON_SIZE_SMALL_TOOLBAR));
        $btnReload->connect_simple('clicked', array($this, 'reloadWidgets'));
        $hbox->pack_start($btnReload, false);

        $this->lblStatus = new GtkLabel('');
        $this->lblStatus->set_alignment(0, 0.5);
        $hbox->pack_start($this->lblStatus, true);

        $vbox = new GtkVBox();
        $vbox->pack_start($hbox, false);
        $vbox->pack_start($scrwnd);
        $this->add($vbox);

        $selection = $this->trWidgets->get_selection();
        $selection->set_mode(Gtk::SELECTION_BROWSE);
        $this->sigSelection = $selection->connect_after('changed', array($this, 'selectionChanged'));
    }//function buildLayout()



    function setWidget($widget)
    {
        if ($widget === null) {
            $this->modWidgets->clear();
        } else {
            $this->widget = $widget;
            $this->addWidgetToModel(null, $this->widget);
            $this->trWidgets->expand_all();
        }
    }//function setWidget($widget)



    function reloadWidgets()
    {
        $this->modWidgets->clear();
        $this->setWidget($this->widget);
    }//function reloadWidgets()



    function setStatus($strText = null, $bError = true)
    {
        if ($strText === null) {
            $this->lblStatus->set_text('');
        } else {
            if ($bError) {
                $this->lblStatus->set_markup('<span color="red">' . $strText . '</span>');
            } else {
                $this->lblStatus->set_text($strText);
            }
        }
    }//function setStatus($strText = null, $bError = true)



    function addWidgetToModel($parent, $widget)
    {
        $arChildren = array();
        if (is_a($widget, 'GtkContainer')) {
            $arChildren = $widget->get_children();
        }
        $iter = $this->modWidgets->append($parent, array($widget, $widget->get_name(), get_class($widget), get_parent_class($widget), count($arChildren)));
        $widget->connect('focus-in-event', array($this, 'selectWidget'));

        if (count($arChildren) > 0) {
            for ($nA = 0; $nA < count($arChildren); $nA++) {
                $this->addWidgetToModel($iter, $arChildren[$nA]);
            }
        }

    }//function addWidgetToModel($widget)



    function selectionChanged($selection)
    {
        list($model, $iter) = $selection->get_selected();
        if ($iter === null) {
            return;
        }
        $rootwidget = $model->get_value($iter, 0);

        if ($rootwidget->window === null) {
            $this->setStatus(sprintf(self::$strNotRealized, $model->get_value($iter, 1)));
            return;
        } else {
            $this->setStatus();
        }

        $allocation = $rootwidget->allocation;
        $x = $allocation->x;
        $y = $allocation->y;
        $width = $allocation->width;
        $height= $allocation->height;
        $arWidgets = array($rootwidget);
//        $arWidgets = $this->appendChildrenToArray($rootwidget, $arWidgets);

        foreach ($arWidgets as $widget) {
            if ($widget->window !== null) {
//                list($newx, $newy) = $widget->translate_coordinates($rootwidget, $x, $y);
//                list($neww, $newh) = $widget->translate_coordinates($rootwidget, $width, $height);
//                $widget->window->draw_rectangle($widget->style->black_gc, false, $newx, $newy, $neww - 1, $newh - 1);
//                $widget->window->draw_rectangle($widget->style->black_gc, false, $newx + 1, $newy + 1, $neww - 3, $newh - 3);

                if (in_array(get_class($widget), self::$arSpecialWidgets)) {
                    $this->arStyles[] = array($widget, $widget->get_style());
                    $style = $widget->get_style();
                    $style = $style->copy();
                    $style->base[Gtk::STATE_NORMAL] = GdkColor::parse('#F00');
                    $widget->set_style($style);

                    $widget->show();
                    list($x, $y, $width, $height, $depth) = $widget->window->get_geometry();
                    $widget->queue_draw_area($x, $y, $width, $height);
                } else {
                    $widget->window->draw_rectangle($widget->style->black_gc, false, $x, $y, $width - 1, $height - 1);
                    $widget->window->draw_rectangle($widget->style->black_gc, false, $x + 1, $y + 1, $width - 3, $height - 3);
//                    $widget->window->draw_rectangle($widget->style->black_gc, false, $x + 2, $y + 2, $width - 5, $height - 5);
                }
            }
        }

        Gtk::timeout_add(500, array($this, 'refresh'), $rootwidget);
    }//function selectionChanged($selection)



    function appendChildrenToArray($rootwidget, $arWidgets)
    {
        if (is_a($rootwidget, 'GtkContainer')) {
            $arChildren = $rootwidget->get_children();
            foreach ($arChildren as $nId => $dontuseit) {
                $arWidgets[] = $arChildren[$nId];
                $arWidgets   = $this->appendChildrenToArray($arChildren[$nId], $arWidgets);
            }
        }
        return $arWidgets;
    }//function appendChildrenToArray($rootwidget, $arWidgets)



    function refresh($widget)
    {
        if ($widget->window === null) {
            return;
        }

        if (in_array(get_class($widget), self::$arSpecialWidgets)) {
            //restore color
            foreach ($this->arStyles as $nId => $dontuseit) {
                if ($this->arStyles[$nId][0] == $widget) {
                    $widget->set_style($this->arStyles[$nId][1]);
                    unset($this->arStyles[$nId]);
                    break;
                }
            }
        }

        list($x, $y, $width, $height, $depth) = $widget->window->get_geometry();
        $widget->queue_draw_area($x, $y, $width, $height);
    }//function refresh($widget)



    function selectWidget($widget)
    {
        if ($this->trWidgets->window !== null) {
            $this->modWidgets->foreach(array($this, 'findWidget'), $widget);
        }
    }//function selectWidget($widget)



    function findWidget($store, $path, $iter, $widget)
    {
        if ($store->get_value($iter, 0) === $widget) {
            //found!
            $this->trWidgets->get_selection()->block($this->sigSelection);
            $this->trWidgets->get_selection()->select_path($path);
            $this->trWidgets->scroll_to_cell($path);
            $this->trWidgets->get_selection()->unblock($this->sigSelection);
            return true;//stop iterating now
        }
    }//function findWidget($store, $path, $iter, $widget)

}//class Dev_GuiInspector extends GtkWindow
?>